package other;

import org.junit.jupiter.api.Test;

import java.util.Random;
import java.util.concurrent.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class UtilTest {

    @Test
    public void testCondition() throws InterruptedException {
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        new Thread(() -> {
            lock.lock();
            try {
                System.out.println("Thread 1 start");
                try {
                    // 等待并释放锁
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread 1 is waken up");
            } finally {
                lock.unlock();
            }
        }).start();

        new Thread(() -> {
            lock.lock();
            try {
                System.out.println("Thread 2 start");
                try {
                    Thread.sleep(3000);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
                // 唤醒condition等待的线程，此时锁被当前线程持有，其他线程需等待锁
                condition.signal();
                System.out.println("Thread 2 ended");
            } finally {
                lock.unlock();
            }
        }).start();
        Thread.sleep(4100);
    }


    /**
     * CountDownLatch的计数器只能使用一次;
     * CyclicBarrier的计数器可以使用reset()方法重置。所以CyclicBarrier能处理更为复杂的业务场景。
     *      例如，如果计算发生错误，可以重置计数器，并让线程重新执行一次
     */
    @Test
    public void testCountDownLatch() throws InterruptedException {
        int totalThread = 3;
        CountDownLatch countDown = new CountDownLatch(totalThread);
        for (int i = 0; i < totalThread; i++) {
            final String threadName = "Thread " + i;
            new Thread(() -> {
                System.out.println(String.format("%s %s", threadName, "started"));
                try {
                    Thread.sleep(new Random().nextInt(1000));
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
                System.out.println(String.format("%s %s", threadName, "ended"));
                countDown.countDown();
            }).start();
        }
        countDown.await();
        System.out.println("CountDownLatch为0时，才会继续执行");
        Thread.sleep(1100);
    }

    @Test
    public void testCyclicBarrier() throws InterruptedException {
        int totalThread = 5;
        CyclicBarrier barrier = new CyclicBarrier(totalThread);
        for (int i = 0; i < totalThread; i++) {
            String threadName = "Thread " + i;
            new Thread(() -> {
                System.out.println(String.format("%s %s", threadName, "is waiting"));
                try {
                    //阻塞在同步点，等所有线程都到达时，才会继续执行
                    barrier.await();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
                System.out.println(String.format("%s %s", threadName, "ended"));
            }).start();
        }
        Thread.sleep(100);
    }

    @Test
    public void testSemaphore() throws InterruptedException {
        int totalThread = 5;
        Semaphore s = new Semaphore(2); //控制同时并发的线程数量
        for (int i = 0; i < totalThread; i++) {
            String threadName = "Thread " + i;
            new Thread(() -> {
                try {
                    //申请Semaphore
                    s.acquire();
                    Thread.sleep(3000);
                    System.out.println(threadName + "executed");
                } catch (Exception ex) {
                    ex.printStackTrace();
                } finally {
                    //释放Semaphore
                    s.release();
                }
            }).start();
        }
        Thread.sleep(10000);
    }

    @Test
    public void testPhaser() throws InterruptedException {
        int parties = 3;
        int phases = 4;
        final Phaser phaser = new Phaser(parties) {
            @Override
            //每完成一个阶段都会调用onAdvance
            protected boolean onAdvance(int phase, int registeredParties) {
                System.out.println("====== Phase : " + phase + " ======");
                return registeredParties == 0;
            }
        };
        for (int i = 0; i < parties; i++) {
            int threadId = i;
            new Thread(() -> {
                for (int j = 0; j < phases; j++) {
                    System.out.println(String.format("Thread %s, phase %s", threadId, j));
                    phaser.arriveAndAwaitAdvance();
                }
            }).start();
        }
        Thread.sleep(1000);
    }
}
